package cetcbigdata.da.base;

import com.alibaba.datax.common.element.*;
import com.alibaba.datax.common.plugin.RecordSender;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.charset.Charset;
import java.sql.Connection;
import java.text.SimpleDateFormat;
import java.util.*;



/**
 * @author YuanGongPing
 * @version 0.1
 * @description JiaoYiCuoHeBase
 * @since 2022/5/24 19:03
 */


public abstract class Base {
    public static long coumt = 0;

    public Connection connection = null;

    public static  String errorFlag = "%%%%%%%%%%%%%%%%%%%%%%";

    public static Logger logger = LoggerFactory.getLogger(Base.class);

    private  static  int socketTimeout = 90000;

    private  static  int connectionRequestTimeout = 60000;

    private  static  int connectTimeout = 90000;

    // 每个请求随机睡眠时间，上限值，单位 微秒
    private  static  int sleepMax = 1500;

    // 每个请求随机睡眠时间，下限值，单位 微秒
    private  static  int sleepMin = 100;

    // 请求失败，重试次数
    private  static  int reTryNum = 3;


    public abstract void getData(RecordSender recordSender, List<Object> fieldsList);

    public abstract JSONObject getDataDemo();

    /****
     * 将一条JSONObject记录 保存至 writer中
     * @param item
     * @param recordSender
     * @param fieldsList
     */
    public static void processItem(JSONObject item, RecordSender recordSender, List<Object> fieldsList){
        // 定义一条记录
        Record record = recordSender.createRecord();
        // 定义字段一条记录， 如: {"name": "xxx", "type": "string"}
        JSONObject fieldItemJson;
        // 遍历所有字段
        for (Object fieldItem : fieldsList) {
            // 将Object 转为 JSONObject， 赋值给 fieldItemJson
            fieldItemJson = (JSONObject) JSONObject.toJSON(fieldItem);
            // 字段的key
            String fieldName = fieldItemJson.getString("name");
            // 字段类型
            String fieldType = fieldItemJson.getString("type");
            // 获取字段值
            String valueString = item.getString(fieldName);
            // 编码格式转换
            // String columnValue = new String(columnValueTemp.getBytes("iso-8859-1"), "utf-8");
            String columnValue = valueString;
            //  Record 一条记录中添加字段
            record.addColumn(convert2column(columnValue, fieldType));
        }
        // 发送一条记录到writer中
        recordSender.sendToWriter(record);
    }

    /****
     * 将字段值 转能成Column 的指定类型
     * @param value 待转换的值
     * @param fieldType 待转换的类型
     * @return Column
     */
    public static Column convert2column(String value, String fieldType){
        Column column = null;
        // TODO 其他类型
        if ("string".equals(fieldType)) {
            column = new StringColumn(value);
        } else if ("long".equals(fieldType)) {
            try {
                column = new LongColumn(value);
            } catch (Exception e) {
                throw new IllegalArgumentException(String.format("类型转换错误, 无法将[%s] 转换为[%s]", value, "LONG"));
            }
        } else if ("double".equals(fieldType)) {
            try {
                column = new DoubleColumn(value);
            } catch (Exception e) {
                throw new IllegalArgumentException(String.format("类型转换错误, 无法将[%s] 转换为[%s]", value, "DOUBLE"));
            }
        } else if ("boolen".equals(fieldType)) {
            try {
                column = new BoolColumn(value);
            } catch (Exception e) {
                throw new IllegalArgumentException(String.format("类型转换错误, 无法将[%s] 转换为[%s]", value, "BOOLEAN"));
            }
        }
        return column;
    }

    /****
     * 获取当前时间，格式2021-02-05 01:19:85
     * @return 时间格式字符串 //设置日期格式
     */
    public static String getCurrentTime(String fm){
        SimpleDateFormat df = new SimpleDateFormat(fm);
        return df.format(new Date());
    }

    /**
     * get请求
     * @param url
     * @param headers
     * @param params
     * @return
     */
    public static  String getReq(String url, JSONObject headers, JSONObject params) {
        int retry = 0;
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        String result = null;
        try {
            while (retry <= reTryNum) {
                // 通过址默认配置创建一个httpClient实例
                httpClient = HttpClients.createDefault();
                HttpGet httpGet;
                /*************    请求参数  ***************/
                if (null != params && params.size() > 0) {
                    List<NameValuePair> nvps = new ArrayList<NameValuePair>();
                    // 通过map集成entrySet方法获取entity
                    Set<Map.Entry<String, Object>> entrySet = params.entrySet();
                    // 循环遍历，获取迭代器
                    Iterator<Map.Entry<String, Object>> iterator = entrySet.iterator();
                    while (iterator.hasNext()) {
                        Map.Entry<String, Object> mapEntry = iterator.next();
                        nvps.add(new BasicNameValuePair(mapEntry.getKey(), mapEntry.getValue().toString()));
                    }
                    httpGet = new HttpGet(new URIBuilder(url).addParameters(nvps).build());
                } else {
                    httpGet = new HttpGet(url);
                }

                // 设置请求头信息
                /**********             设置请求头                          **********/
                if (null != headers && headers.size() > 0) {
                    Set<Map.Entry<String, Object>> entrySet = headers.entrySet();
                    // 循环遍历，获取迭代器
                    Iterator<Map.Entry<String, Object>> iterator = entrySet.iterator();
                    while (iterator.hasNext()) {
                        Map.Entry<String, Object> mapEntry = iterator.next();
                        httpGet.addHeader(mapEntry.getKey(), mapEntry.getValue().toString());
                    }
                }

                // 设置配置请求参数
                RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeout)// 连接主机服务超时时间
                        .setConnectionRequestTimeout(connectionRequestTimeout)// 请求超时时间
                        .setSocketTimeout(socketTimeout)// 数据读取超时时间
                        .build();
                // 为httpGet实例设置配置
                httpGet.setConfig(requestConfig);
                // 执行get请求得到返回对象
                try {
                    response = httpClient.execute(httpGet);
                    // 通过返回对象获取返回数据
                    HttpEntity entity = response.getEntity();
                    // 通过EntityUtils中的toString方法将结果转换为字符串
                    result = EntityUtils.toString(entity);
                }catch ( Exception e){
                    result = errorFlag;
                }
                if(result.equals(errorFlag)){
                    retry ++;
                    // 随机生成100 - 2000 的随机数，作为睡眠
                    sleep( sleepMax, sleepMin);
                    logger.info(String.format("--------------重试 %s 次---------------------: %s", retry, url));
                }else {
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            result = errorFlag;
        } finally {
            // 关闭资源
            if (null != response) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != httpClient) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    /**
     * post 请求
     * @param url
     * @param params
     * @return
     */
    public static String postReq(String url, JSONObject params) {
        int retry = 0;
        String result = null;
        while (retry <= reTryNum) {
            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
            HttpPost httpPost = new HttpPost(url);
            httpPost.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, connectionRequestTimeout);
            httpPost.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, connectTimeout);
            StringEntity stringEntity = new StringEntity(params.toString(), "UTF-8");
            httpPost.setEntity(stringEntity);
            httpPost.setHeader("Content-Type", "application/json;charset=utf8");
            CloseableHttpResponse response = null;
            try {
                // 由客户端执行(发送)Post请求
                response = httpClient.execute(httpPost);
                // 从响应模型中获取响应实体
                HttpEntity responseEntity = response.getEntity();
                if (responseEntity != null) {
                    InputStream respIs = responseEntity.getContent();
                    byte[] respBytes = IOUtils.toByteArray(respIs);
                    result = new String(respBytes, Charset.forName("UTF-8"));
                }
            }
            catch (Exception e) {
                e.printStackTrace();
                result = errorFlag;
            }
            finally {
                try {
                    // 释放资源
                    if (httpClient  != null) {
                        httpClient .close();
                    }
                    if (response != null) {
                        response.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (result.equals(errorFlag)) {
                retry++;
                // 随机生成100 - 2000 的随机数，作为睡眠
                sleep( sleepMax, sleepMin);
                logger.info(String.format("--------------重试 %s 次---------------------: %s", retry, url) );
            } else {
               break;
            }
        }
        return result;
    }


    /**
     * post 请求
     * @param url
     * @param params
     * @return
     */
    public static String postReq(String url,JSONObject headers, JSONObject params) {
        int retry = 0;
        String result = null;
        while (retry <= reTryNum) {
            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
            HttpPost httpPost = new HttpPost(url);
            httpPost.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, connectionRequestTimeout);
            httpPost.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, connectTimeout);
            StringEntity stringEntity = new StringEntity(params.toString(), "UTF-8");
            httpPost.setEntity(stringEntity);
            if(headers != null){
                for(String key : headers.keySet()){
                    httpPost.setHeader(key, headers.getString(key));
                }
            }
            httpPost.setHeader("Content-Type", "application/json;charset=utf8");
            CloseableHttpResponse response = null;
            try {
                // 由客户端执行(发送)Post请求
                response = httpClient.execute(httpPost);
                // 从响应模型中获取响应实体
                HttpEntity responseEntity = response.getEntity();
                if (responseEntity != null) {
                    InputStream respIs = responseEntity.getContent();
                    byte[] respBytes = IOUtils.toByteArray(respIs);
                    result = new String(respBytes, Charset.forName("UTF-8"));
                }
            }
            catch (Exception e) {
                e.printStackTrace();
                result = errorFlag;
            }
            finally {
                try {
                    // 释放资源
                    if (httpClient  != null) {
                        httpClient .close();
                    }
                    if (response != null) {
                        response.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (result.equals(errorFlag)) {
                retry++;
                // 随机生成100 - 2000 的随机数，作为睡眠
                sleep( sleepMax, sleepMin);
                logger.info(String.format("--------------重试 %s 次---------------------: %s", retry, url) );
            } else {
                break;
            }
        }
        return result;
    }

    /**
     *  post表单请求
     * @param url
     * @param headers
     * @param params
     * @return
     */
    public static String postFormReq(String url, JSONObject headers, JSONObject params) {
        int retry = 0;
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse httpResponse = null;
        String result = null;
        try {
            while (retry < 3) {
                // 创建httpClient实例
                httpClient = HttpClients.createDefault();
                // 创建httpPost远程连接实例
                HttpPost httpPost = new HttpPost(url);
                // 配置请求参数实例
                RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeout)// 设置连接主机服务超时时间
                        .setConnectionRequestTimeout(connectionRequestTimeout)// 设置连接请求超时时间
                        .setSocketTimeout(socketTimeout)// 设置读取数据连接超时时间
                        .build();
                // 为httpPost实例设置配置
                httpPost.setConfig(requestConfig);
                /**********    设置请求头      **********/
                if(null != headers && headers.size() > 0 ){
                    Set<Map.Entry<String, Object>> entrySet = headers.entrySet();
                    // 循环遍历，获取迭代器
                    Iterator<Map.Entry<String, Object>> iterator = entrySet.iterator();
                    while (iterator.hasNext()) {
                        Map.Entry<String, Object> mapEntry = iterator.next();
                        httpPost.addHeader(mapEntry.getKey(), mapEntry.getValue().toString());
                    }
                }
                /**********             封装post请求参数                          **********/
                if (null != params && params.size() > 0) {
                    List<NameValuePair> nvps = new ArrayList<NameValuePair>();
                    // 通过map集成entrySet方法获取entity
                    Set<Map.Entry<String, Object>> entrySet = params.entrySet();
                    // 循环遍历，获取迭代器
                    Iterator<Map.Entry<String, Object>> iterator = entrySet.iterator();
                    while (iterator.hasNext()) {
                        Map.Entry<String, Object> mapEntry = iterator.next();
                        nvps.add(new BasicNameValuePair(mapEntry.getKey(), mapEntry.getValue().toString()));
                    }
                    httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
                }
                // httpClient对象执行post请求,并返回响应参数对象
                try {
                    httpResponse = httpClient.execute(httpPost);
                    // 从响应对象中获取响应内容
                    HttpEntity entity = httpResponse.getEntity();
                    result = EntityUtils.toString(entity);
                }catch ( Exception e){
                    result = errorFlag;
                }
                if(result.equals(errorFlag)){
                    retry ++;
                    // 随机生成100 - 2000 的随机数，作为睡眠
                    sleep( sleepMax, sleepMin);
                    logger.info(String.format("--------------重试 %s 次---------------------: %s", retry, url));
                }else {
                    break;
                }
            }
        } catch (Exception e) {
                e.printStackTrace();
        } finally {
            // 关闭资源
            if (null != httpResponse) {
                try {
                    httpResponse.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != httpClient) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    /*******
     *  判断是否为null 或者 空字符串
     * @param str
     * @return
     */
    public static boolean isNotBlankOrNull(Object str){
        return str != null && !str.toString().equals("");
    }

    private static  void sleep(int max, int min){
        // 随机生成200 - 3000 的随机数，作为睡眠
        int interval = (int) ((max - min + 1) * Math.random() + min);
        try {
            Thread.sleep(interval);
        }catch ( Exception e){
            e.printStackTrace();
        }
    }

    // 结果封装
    public static JSONObject processResult(String listUrl, String listPageHtml, String detailUrl,
                                           String detailHtml, JSONObject content, String region, String module){
        JSONObject result = new JSONObject();
        result.put("region", region);
        result.put("module",  module);
        result.put("list_url", listUrl);
        result.put("list_page_html", listPageHtml);
        result.put("detail_url", detailUrl);
        result.put("detail_html", detailHtml);
        result.put("content", content.toJSONString());
        return result;
    }


    public static void printDataCount(int interval){
        if((coumt % interval) == 0){
            logger.info("完成数据采集--"+ coumt);
        }
        coumt += 1;
    }
}